﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using eWallet.Serialization;
using System.Text;

namespace eWallet.Security.Cryptography
{
	public sealed class CertificationCryptoModule : CryptoModule
	{

		public CertificationCryptoModule(X509Certificate2 certificate) : this(new X509Certificate2Collection(certificate)) { }

		public CertificationCryptoModule(X509Certificate2Collection certificates)
		{
			if (null == certificates)
				throw new ArgumentNullException("certificates");

			if (certificates.Count == 0)
				throw new ArgumentException("The certificate collection cannot be empty.", "certificates");

			this.Certificates = certificates;
		}

		private X509Certificate2Collection Certificates;

		public override EncryptionMethod EncryptionMethod
		{
			get { return EncryptionMethod.Certificate; }
		}



		public override byte[] Decrypt(byte[] cipher)
		{
			List<X509Certificate2> list = new List<X509Certificate2>(this.Certificates.Cast<X509Certificate2>());
			var cert = list.Find(c => c.HasPrivateKey);

			if (null == cert)
				throw new CryptographicException("The collection of certificates specified does not contain at least one certificate that contains also the private key. Cannot decrypt.");

			EnvelopedCms envelope = new EnvelopedCms();
			envelope.Decode(cipher);
			envelope.Decrypt(this.Certificates);
			return envelope.ContentInfo.Content;
		}

		public override byte[] Encrypt(byte[] data)
		{
			EnvelopedCms envelope = new EnvelopedCms(new ContentInfo(data));
			CmsRecipientCollection recipients = new CmsRecipientCollection(SubjectIdentifierType.IssuerAndSerialNumber, this.Certificates);
			envelope.Encrypt(recipients);
			return envelope.Encode();
		}

		public override string GetDescription()
		{
			StringBuilder builder = new StringBuilder();
			foreach (var cert in this.Certificates)
			{
				builder.AppendLine(cert.ToString());
			}

			return builder.ToString();
		}

	}
}
